#include "CCreditCurve.h"

CCreditCurve::CCreditCurve()
{
	yc.ReadSwapFile("input.txt");
	R = 0.4;
	NumOfPeriodsInYear = 1;
}

CCreditCurve::~CCreditCurve()
{
}

double CCreditCurve::GetRecoveryRate()
{
	return R;
}

void CCreditCurve::SetRecoveryRate(double RecoveryRate)
{
	R = RecoveryRate;
}

long CCreditCurve::GetFrequency()
{
	return NumOfPeriodsInYear;
}

void CCreditCurve::SetFrequency(long Frequency)
{
	NumOfPeriodsInYear = Frequency;
}

int CCreditCurve::ReadCDSFile(string cdsfile)
{
	double	cdsBid, cdsAsk, cdsMid, cdsPrev;
	double	delta;
	char	temp[8];
	int		i,j;

	ifstream cdsStream(cdsfile.data());

	if (!cdsStream.is_open())
	{
		cout << "Input file Error! " << endl;

		return -1;
	}

	i = 0;
	while (cdsStream >> cdsBid && cdsStream >> cdsAsk)
	{
		cdsMid = ((cdsBid + cdsAsk) / 2) / 10000;

		if (i<=5)
		{
			S.push_back(cdsMid);
		}
		else if (i>5 && i<7)
		{
			S.push_back((cdsMid + cdsPrev) / 2);
			S.push_back(cdsMid);
		}
		else if (i>=7)
		{
			delta = (cdsMid - cdsPrev) / 3;

			for (j=1;j<3;j++)
				S.push_back(cdsPrev + j * delta);

			S.push_back(cdsMid);
		}

		cdsPrev = cdsMid;
		cdsStream.getline(temp, 8);
		i++;
	}

	cdsStream.close();

	if (GenerateQ() != 0)
		return -1;

	if (GenerateCumQ() != 0)
		return -1;

	if (GenerateH() != 0)
		return -1;

/////////////////////////////////////
//	
	ofstream Stream_Q("Q.txt");
	for (i=0;i<Q.size();i++)
		Stream_Q << Q[i] << "\n";
	Stream_Q.close();

	ofstream Stream_CumQ("CumQ.txt");
	for (i=0;i<CumQ.size();i++)
		Stream_CumQ << CumQ[i] << "\n";
	Stream_CumQ.close();

	ofstream Stream_CreditSpread("CreditSpread.txt");
	double d;
	for (d=0;d<10.1;d+=0.1)
		Stream_CreditSpread << CreditSpread(d) << "\n";
	Stream_CreditSpread.close();

	ofstream Stream_HazardRate("HazardRate.txt");
	for (i=0;i<H.size();i++)
		Stream_HazardRate << H[i] << "\n";
	Stream_HazardRate.close();

	ofstream Stream_SurvivalProbability("SurvivalProbability.txt");
	for (i=0;i<11;i++)
		Stream_SurvivalProbability << SurvivalProbability(i) << "\n";
	Stream_SurvivalProbability.close();

/////////////////////////////////////
	return 0;
}

double CCreditCurve::DF(long nPeriod)
{
	return yc.DiscountFactor((double)nPeriod / NumOfPeriodsInYear);
}

int CCreditCurve::GenerateCumQ()
{
	CumQ.push_back(0);

	for (int i = 0;i<Q.size();i++)
	{
		CumQ.push_back(CumQ[i] + Q[i]);
	}

	return 0;
}

int CCreditCurve::GenerateH()
{
	H.push_back(0);

	for (int i=0;i<Q.size();i++)
	{
		H.push_back(Q[i] / (1 - CumQ[i]));
	}

	return 0;
}

double CCreditCurve::CumulativeQ(double time)
{
	long	i = (long)(time * NumOfPeriodsInYear);
	double	k = time * NumOfPeriodsInYear - i;
	double	q = 0;

	if (CumQ.size() < (NUM_OF_PERIODS_IN_INPUT_FILE + 1) || time < 0)
		return -1;

	if (time >= (NUM_OF_PERIODS_IN_INPUT_FILE / NumOfPeriodsInYear))
	{
		q = CumQ[NUM_OF_PERIODS_IN_INPUT_FILE];
	}
	else
	{
		q = CumQ[i+1] * k + CumQ[i] * (1 - k);
	}

	return q;
}

double CCreditCurve::DiscountFactor(double time)
{
	return (yc.DiscountFactor(time) * (1 - CumulativeQ(time)));
}

double CCreditCurve::HazardRate(double time)
{
	long	i = (long)(time * NumOfPeriodsInYear);
	double	k = time * NumOfPeriodsInYear - i;
	double	h = 0;

	if (H.size() < (NUM_OF_PERIODS_IN_INPUT_FILE + 1) || time < 0)
		return -1;

	if (time >= (NUM_OF_PERIODS_IN_INPUT_FILE / NumOfPeriodsInYear))
	{
		h = H[NUM_OF_PERIODS_IN_INPUT_FILE];
	}
	else
	{
		h = H[i+1] * k + H[i] * (1 - k);
	}

	return h;
}

double CCreditCurve::CreditSpread(double time)
{
	if (time <= 0)
		return 0;
	else
		return (- log(1 - CumulativeQ(time)) / time);
}

double CCreditCurve::SurvivalProbability(double time)
{
	return (1 - CumulativeQ(time));
}

int CCreditCurve::GenerateQ()
{
	double first, prev;

	for (int i=1;i<S.size();i++)
	{
		first = 1 / (S[i] + (1 - R));

		if (i == 1)
		{
			Q.push_back(first * S[1]);
		}
		else if (i == 2)
		{
			prev = DF(1) * (S[1] - (Q[0] * (1 - R)) / (1 - Q[0]));

			Q.push_back(first * (S[2] + (1 / DF(2)) * prev));
		}
		else if (i == 3)
		{
			prev = (1 / (1 - Q[1])) * (prev - Q[1] * (1 - R) * DF(2));

			Q.push_back(first * (S[3] + (1 / DF(3)) * (S[2] * DF(2) + prev)));
		}
		else
		{
			prev = (1 / (1 - Q[i-2])) * (S[i-2] * DF(i-2) - Q[i-2] * (1-R) * DF(i-1) + prev);

			Q.push_back(first * (S[i] + (1 / DF(i)) * (S[i-1] * DF(i-1) + prev)));
		}
	}

	return 0;
}
